/**
 * @file	spi.c
 * @author	chipsea
 * @brief	Contains all functions support for spi driver
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */
#include "sdk_config.h"
#include "rom_sym_def.h"
#include "gpio.h"
#include "error.h"
#include <string.h>
#include "pwrmgr.h"
#include "clock.h"
#include "log.h"
#include "spi.h"
#include "dma.h"
#include "jump_function.h"

#define DMAC_USE            1


/**
* @struct SpiBufCtl_t
* @brief spi buffer information
*/
typedef struct {
	uint16_t  bufOffset;
	uint16_t  bufSize;
	uint8_t*  buf;
} SpiBufCtl_t;

/**
* @struct SpiCtl_t
* @brief spi control information
*/
typedef struct {
	bool    	enable;
	spi_Cfg_t	cfg;
	uint8_t   	busy;
	SpiBufCtl_t txBufCtl;
	SpiBufCtl_t rxBufCtl;	//It's valid when role is master
} SpiCtl_t;

static SpiCtl_t spiCtl[2];


#define  SPI_USE_TIMEOUT    1
#define  SPI_OP_TIMEOUT     1000        //100ms for an Byte operation
#if(SPI_USE_TIMEOUT == 1)
    #define SPI_INIT_TOUT(to)            int to = hal_systick()
    #define SPI_CHECK_TOUT(to, timeout) {if(hal_ms_intv(to) > timeout){return ERR_TIMEOUT;}}
#else
    #define SPI_INIT_TOUT(to)
    #define SPI_CHECK_TOUT(to, timeout)
#endif

static void HalSpiWriteFifo(AP_SSI_TypeDef* SPIx, uint8_t len, uint8_t* tx_rx_ptr)
{
    uint8_t i=0;
    HAL_ENTER_CRITICAL_SECTION();

    while(i<len)
    {
        SPIx->DataReg = *(tx_rx_ptr+i);
        i++;
    }

    HAL_EXIT_CRITICAL_SECTION();
}


void HalSpiIntEnable(SPI_INDEX_e index, uint32_t mask)
{
    if(index == SPI0)
    {
        AP_SPI0->IMR = mask & 0x11;
        JUMP_FUNCTION(SPI0_IRQ_HANDLER) = (uint32_t)&HalSpi0IRQHandler;
    }
    else
    {
        AP_SPI1->IMR = mask & 0x11;
        JUMP_FUNCTION(SPI1_IRQ_HANDLER) = (uint32_t)&HalSpi1IRQHandler;
    }

    NVIC_EnableIRQ((IRQn_Type)(SPI0_IRQn + index));
    NVIC_SetPriority((IRQn_Type)(SPI0_IRQn + index), IRQ_PRIO_HAL);
}

static void HalSpiIntDisable(SPI_INDEX_e index)
{
    NVIC_DisableIRQ((IRQn_Type)(SPI0_IRQn + index));
    if(index == SPI0)
    {
        AP_SPI0->IMR = 0x00;
    }
    else
    {
        AP_SPI1->IMR = 0x00;
    }
}

static void HalSpiMasterHandle(SPI_INDEX_e id, AP_SSI_TypeDef* SPIx)
{
    volatile uint8_t spi_irs_status;
    spi_evt_t evt;
    uint8_t i, cnt;
    
    spi_irs_status = SPIx->ISR;
    
    if(spi_irs_status & TRANSMIT_FIFO_EMPTY)
    {
        cnt = 8 - SPIx->TXFLR;

        for(i = 0; i< cnt; i++)
        {
            if(spiCtl[id].txBufCtl.bufOffset >= spiCtl[id].txBufCtl.bufSize)
            {
                SPIx->IMR = 0x10;
                if(spiCtl[id].cfg.force_cs == true)
                {
                    while(SPIx->SR & 0x01);
                    HalGpioFmuxEnable(spiCtl[id].cfg.ssn_pin, Bit_ENABLE);
                }
                spiCtl[id].busy = false;
                evt.id = id;
                evt.evt = SPI_TX_COMPLETED;
                if(spiCtl[id].cfg.evt_handler)
                {
                    spiCtl[id].cfg.evt_handler(&evt);
                }
                
                break;
            }
            
            if(spiCtl[id].txBufCtl.buf)
            {
                SPIx->DataReg = spiCtl[id].txBufCtl.buf[spiCtl[id].txBufCtl.bufOffset++];
            }
            else
            {
                if(!(spi_irs_status & RECEIVE_FIFO_FULL))
                {
                    if(spiCtl[id].rxBufCtl.buf)
                    {
                        spiCtl[id].rxBufCtl.buf[spiCtl[id].rxBufCtl.bufOffset++] = SPIx->DataReg;
                    }
                }
                spiCtl[id].txBufCtl.bufOffset++;
                SPIx->DataReg = 0;
            }
        }
    }
    if(spi_irs_status & RECEIVE_FIFO_FULL)
    {
        cnt = SPIx->RXFTLR + 1;
        for(i = 0; i< cnt; i++)
        {
            if(spiCtl[id].rxBufCtl.buf)
            {
                spiCtl[id].rxBufCtl.buf[spiCtl[id].rxBufCtl.bufOffset++] = SPIx->DataReg;
            }
            else
            {
                VOID (SPIx->DataReg & 0xff);
            }
        }

        if(spiCtl[id].rxBufCtl.bufOffset >= spiCtl[id].rxBufCtl.bufSize)
        {
            if(spiCtl[id].cfg.force_cs == true)
                HalGpioFmuxEnable(spiCtl[id].cfg.ssn_pin, Bit_ENABLE);

            spiCtl[id].busy = false;
            spiCtl[id].rxBufCtl.buf = NULL;
            spiCtl[id].rxBufCtl.bufOffset = 0;
            evt.id = id;
            evt.evt = SPI_RX_COMPLETED;
            hal_pwrmgr_unlock((per_module_t)(MOD_SPI0 + id));
            if(spiCtl[id].cfg.evt_handler)
            {
                spiCtl[id].cfg.evt_handler(&evt);
            }
        }
        if(spiCtl[id].txBufCtl.bufOffset >= spiCtl[id].txBufCtl.bufSize)
        {
            spiCtl[id].busy = false;
            evt.id = id;
            evt.evt = SPI_TX_COMPLETED;
            if(spiCtl[id].cfg.evt_handler)
            {
                spiCtl[id].cfg.evt_handler(&evt);
            }
        }
    }
    
}

static void HalSpiSlaveHandle(SPI_INDEX_e id, AP_SSI_TypeDef* SPIx)
{
    volatile uint8_t spi_irs_status;
    spi_evt_t evt;
    uint16_t i, cnt;
    
    spi_irs_status = SPIx->ISR;

    if(spi_irs_status & TRANSMIT_FIFO_EMPTY)
    {
        cnt = 8 - SPIx->TXFLR;

        for(i = 0; i< cnt; i++)
        {
            
            if(spiCtl[id].txBufCtl.bufOffset >= spiCtl[id].txBufCtl.bufSize)
            {
                SPIx->DataReg = 0;
                SPIx->IMR = 0x10;
                break;
            }

            if(spiCtl[id].txBufCtl.buf && spiCtl[id].busy)
            {
                SPIx->DataReg = spiCtl[id].txBufCtl.buf[spiCtl[id].txBufCtl.bufOffset++];
            }
            else
            {
                SPIx->DataReg = 0;
            }
        }
    }

    if(spi_irs_status & RECEIVE_FIFO_FULL)
    {
        volatile uint32_t garbage;
        cnt = SPIx->RXFLR;

        if(spiCtl[id].rxBufCtl.buf)
        {
            for(i = 0; i< cnt; i++)
            {
                if(spiCtl[id].rxBufCtl.bufSize > spiCtl[id].rxBufCtl.bufOffset)
                    spiCtl[id].rxBufCtl.buf[spiCtl[id].rxBufCtl.bufOffset++] = SPIx->DataReg;
                else
                    garbage = SPIx->DataReg;
            }
        }
        else if(!spiCtl[id].busy)
        {
            uint8_t rxbuf[16];

            for(i = 0; i< cnt; i++)
            {
                *(rxbuf+i) = SPIx->DataReg;
            }
            
            evt.id = id;
            evt.evt = SPI_RX_DATA_S;
            evt.data = rxbuf;
            evt.len = cnt;
            spiCtl[id].cfg.evt_handler(&evt);
        }
        else
        {
            garbage = SPIx->DataReg;
            spiCtl[id].rxBufCtl.bufOffset += cnt;
        }
        if(spiCtl[id].busy && spiCtl[id].rxBufCtl.bufOffset >= spiCtl[id].txBufCtl.bufSize)
        {
            spiCtl[id].busy = false;
            spiCtl[id].txBufCtl.buf = NULL;
            spiCtl[id].txBufCtl.bufOffset = 0;
            spiCtl[id].rxBufCtl.bufOffset = 0;
            evt.id = id;
            evt.evt = SPI_TX_COMPLETED;
            spiCtl[id].cfg.evt_handler(&evt);
        }
    }
}

/**************************************************************************************
@fn          HalSpi0IRQHandler

@brief       This function process for spi0 interrupt,when use int please consummate its callbackfunction

input parameters

@param       None.

output parameters

@param       None.

@return      None.
 **************************************************************************************/
void __attribute__((used)) HalSpi0IRQHandler(void)
{
    if(!spiCtl[0].enable)
        return;

    if(spiCtl[0].cfg.is_slave)
        HalSpiSlaveHandle(SPI0, AP_SPI0);
    else
        HalSpiMasterHandle(SPI0, AP_SPI0);
}

/**************************************************************************************
@fn          HalSpi1IRQHandler

@brief       This function process for spi1 interrupt,when use int please consummate its callbackfunction

input parameters

@param       None.

output parameters

@param       None.

@return      None.
 **************************************************************************************/
void __attribute__((used)) HalSpi1IRQHandler(void)
{
    if(!spiCtl[1].enable)
        return;

    if(spiCtl[1].cfg.is_slave)
        HalSpiSlaveHandle(SPI1, AP_SPI1);
    else
        HalSpiMasterHandle(SPI1, AP_SPI1);
}

/**************************************************************************************
@fn          HalSpiPinInit

@brief       This function process for spi pin initial(4 lines);You can use two spi,spi0 and spi1,should programe by USE_AP_SPIX

input parameters

@param       GPIO_Pin_e sck_pin: define sclk pin
             GPIO_Pin_e ssn_pin: define ssn pin
             GPIO_Pin_e tx_pin: define transmit pin;when use as master,it's mosi pin;corresponding,use as slave,it's miso
             GPIO_Pin_e rx_pin: define receive pin;when use as master,it's miso pin;corresponding,use as slave,it's mosi

output parameters

@param       None.

@return      None.
 **************************************************************************************/
static void HalSpiPinInit(SPI_INDEX_e index, GpioPin_t sck_pin, GpioPin_t ssn_pin, GpioPin_t tx_pin, GpioPin_t rx_pin)
{
    HalGpioFmuxConfig(sck_pin, (gpio_fmux_e)(FMUX_SPI_0_SCK+index*4));
    HalGpioFmuxConfig(ssn_pin, (gpio_fmux_e)(FMUX_SPI_0_SSN+index*4));
    HalGpioFmuxConfig(tx_pin,  (gpio_fmux_e)(FMUX_SPI_0_TX+index*4));
    HalGpioFmuxConfig(rx_pin,  (gpio_fmux_e)(FMUX_SPI_0_RX+index*4));
}

static void HalSpiPinDeinit(GpioPin_t sck_pin, GpioPin_t ssn_pin, GpioPin_t tx_pin, GpioPin_t rx_pin)
{
    HalGpioFmuxEnable(sck_pin, Bit_DISABLE);
    HalGpioFmuxEnable(ssn_pin, Bit_DISABLE);
    HalGpioFmuxEnable(tx_pin, Bit_DISABLE);
    HalGpioFmuxEnable(rx_pin, Bit_DISABLE);
}

#if DMAC_USE
static void HalConfigDmaSpiTx(AP_SSI_TypeDef* SPIx, uint8_t* tx_buf, uint16_t tx_len)
{
    uint8_t index = 0;
    DMA_CH_CFG_t cfgc;
    
    if(SPIx == AP_SPI1)
    {
        index = 1;
    }
    SPIx->DMACR &= 0x01;
    
    cfgc.transf_size = tx_len;
    cfgc.sinc = DMA_INC_INC;

    if(spiCtl[index].cfg.spi_dfsmod == SPI_1BYTE)
    {
        cfgc.src_tr_width = DMA_WIDTH_BYTE;
        cfgc.dst_tr_width = DMA_WIDTH_BYTE;
    }
    else
    {
        cfgc.src_tr_width = DMA_WIDTH_HALFWORD;
        cfgc.dst_tr_width = DMA_WIDTH_HALFWORD;
    }

    cfgc.src_msize = DMA_BSIZE_1;
    cfgc.src_addr = (uint32_t)tx_buf;
    cfgc.dinc = DMA_INC_NCHG;
    cfgc.dst_msize = DMA_BSIZE_1;
    cfgc.dst_addr = (uint32_t)&(SPIx->DataReg);
    cfgc.enable_int = true;
    HalDMAConfigChannel(SPI_DMAC_CH, &cfgc);
    HalDMAStartChannel(SPI_DMAC_CH);
    SPIx->DMACR |= 0x02;
    SPIx->DMATDLR = 0;
}

static void HalConfigDmaSpiRx(AP_SSI_TypeDef* SPIx, uint8_t* rx_buf, uint16_t rx_len)
{
    DMA_CH_CFG_t cfgc;
    
    SPIx->DMACR &= 0x02;
    cfgc.transf_size = rx_len;
    cfgc.sinc = DMA_INC_NCHG;
    cfgc.src_tr_width = DMA_WIDTH_BYTE;
    cfgc.src_msize = DMA_BSIZE_1;
    cfgc.src_addr = (uint32_t)&(SPIx->DataReg);
    cfgc.dinc = DMA_INC_INC;
    cfgc.dst_tr_width = DMA_WIDTH_BYTE;
    cfgc.dst_msize = DMA_BSIZE_1;
    cfgc.dst_addr = (uint32_t)rx_buf;
    cfgc.enable_int = true;
    HalDMAConfigChannel(SPI_DMAC_CH, &cfgc);
    HalDMAStartChannel(SPI_DMAC_CH);
    SPIx->DMACR |= 0x01;
    SPIx->DMARDLR = 0;
}
#endif

static ErrCode_t HalSpiXmitPolling(AP_SSI_TypeDef* SPIx, uint8_t* tx_buf, uint8_t* rx_buf, uint16_t len)
{
    uint16_t tmp_len, i;
    uint16_t tx_size, rx_size;

#if DMAC_USE
    SPI_INDEX_e index = SPI0;
    
    if(SPIx == AP_SPI1)
    {
        index = SPI1;
    }
#endif
    
    tx_size = len;
    rx_size = len;
    SPI_INIT_TOUT(to);
    
#if DMAC_USE
    if(rx_buf && spiCtl[index].cfg.dma_rx_enable)
    {
        HalConfigDmaSpiRx(SPIx, rx_buf, rx_size);
    }
    else if(tx_buf && spiCtl[index].cfg.dma_tx_enable)
    {
        HalConfigDmaSpiTx(SPIx, tx_buf, tx_size);
    }
#endif

    while(1)
    {
#if DMAC_USE
        if( (SPIx->SR&TX_FIFO_NOT_FULL) && (!(spiCtl[index].cfg.dma_tx_enable)) )
#else
        if(SPIx->SR & TX_FIFO_NOT_FULL && tx_size)
#endif
        {
            tmp_len = 8-SPIx->TXFLR;

            if(tmp_len > tx_size)
                tmp_len = tx_size;

            for(i=0; i<tmp_len; i++)
            {
                SPIx->DataReg = (tx_buf!=NULL)?(*(tx_buf+len-tx_size+i)):0;
            }

            tx_size -= tmp_len;
        }

    #if DMAC_USE
        if( ((rx_buf == NULL) && ((tx_size == 0)||(tx_size && (spiCtl[index].cfg.dma_tx_enable)))) ||
            ((rx_buf != NULL) && (tx_size == 0) && (spiCtl[index].cfg.dma_rx_enable)) )
            break;
        else if( (rx_buf != NULL) && (!(spiCtl[index].cfg.dma_rx_enable)) )
    #else
        if((rx_size == 0) && ((tx_size == 0)))
            break;
        else if(rx_size)
    #endif
        {
            if(SPIx->RXFLR)
            {
                tmp_len = SPIx->RXFLR;

                for(i = 0; i< tmp_len; i++)
                {
                    *rx_buf++= SPIx->DataReg;
                }

                rx_size -= tmp_len;
            }

            if(rx_size == 0)
                break;
        }

        SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT);
    }

#if DMAC_USE
    if((spiCtl[index].cfg.dma_rx_enable) || (spiCtl[index].cfg.dma_tx_enable))
    {
        HalDMAStatusControl(SPI_DMAC_CH);
    }
#endif

    while(SPIx->SR & SPI_BUSY)
    {
        SPI_CHECK_TOUT(to, SPI_OP_TIMEOUT);
    }

    return ERR_NONE;
}
static ErrCode_t HalSpiDisable(SPI_INDEX_e index)
{
	if(index >SPI1)
	{
		return ERR_NOT_SUPPORTED;
	}
    hal_clk_gate_disable((per_module_t)(MOD_SPI0 + index));
    HalSpiPinDeinit(spiCtl[index].cfg.sclk_pin, spiCtl[index].cfg.ssn_pin, spiCtl[index].cfg.MOSI, spiCtl[index].cfg.MISO);
    osal_memset(&spiCtl[index], 0, sizeof(spiCtl));
    return ERR_NONE;
}


static void HalSpi0SleepHandler(void)
{
    if(spiCtl[0].enable)
    {
        HalSpiDisable(SPI0);
    }
}

static void HalSpi1SleepHandler(void)
{
    if(spiCtl[1].enable)
    {
        HalSpiDisable(SPI1);
    }
}

static void HalSpi0WakeupHandler(void)
{
    NVIC_SetPriority((IRQn_Type)SPI0_IRQn, IRQ_PRIO_HAL);
}

static void HalSpi1WakeupHandler(void)
{
    NVIC_SetPriority((IRQn_Type)SPI1_IRQn, IRQ_PRIO_HAL);
}

void HalSpiTmodSet(AP_SSI_TypeDef* SPIx, SPI_TMOD_e mod)
{
    SPIx->SSIEN = 0;
    subWriteReg(&SPIx->CR0,9,8,mod);
    SPIx->SSIEN = 1;
}

void HalSpiDfsSet(SPI_INDEX_e index, SPI_DFS_e mod)
{
    AP_SSI_TypeDef* SPIx = NULL;
    
    SPIx = (index == SPI0) ? AP_SPI0 : AP_SPI1;
    
    SPIx->SSIEN = 0;
    subWriteReg(&SPIx->CR0,3,0,mod);
    SPIx->SSIEN = 1;
    spiCtl[index].cfg.spi_dfsmod = mod;
}

void HalSpiNdfSet(AP_SSI_TypeDef* SPIx, uint16_t len)
{
    SPIx->SSIEN = 0;
    SPIx->CR1 = len-1;
    SPIx->SSIEN = 1;
}

ErrCode_t HalSpiMasterTransfer(AP_SSI_TypeDef* SPIx, SPI_TMOD_e mod, uint8_t* tx_buf, uint8_t* rx_buf, uint16_t len)
{
    int ret;
    SPI_INDEX_e index = SPI0;
    
    if(SPIx != AP_SPI0 && SPIx != AP_SPI1)
    {
        return ERR_NOT_SUPPORTED;
    }
    if(mod > SPI_RXD)
	{
		return ERR_IO_CONFILCT;
	}
    if(len == 0 || (tx_buf == NULL && rx_buf == NULL))
    {
        return ERR_INVALID_DATA;
    }
    
    if(SPIx == AP_SPI1)
    {
        index = SPI1;
    }
    
    if(!spiCtl[index].enable)
    {
        return ERR_NOT_REGISTED;
    }

    if(spiCtl[index].busy)
    {
        return ERR_BUSY;
    }
    
    spiCtl[index].txBufCtl.buf = tx_buf;
    spiCtl[index].txBufCtl.bufOffset = 0;
    spiCtl[index].txBufCtl.bufSize = len;
    
    spiCtl[index].rxBufCtl.buf = rx_buf;
    spiCtl[index].rxBufCtl.bufOffset = 0;
    spiCtl[index].rxBufCtl.bufSize = len;
    
    HalSpiTmodSet(SPIx, mod);

    if(mod > SPI_TXD)  //spi receive only or eeprom read,should set read data len(ndf)
    {
        HalSpiNdfSet(SPIx, len);
    }

    if(spiCtl[index].cfg.force_cs == true)
    {
        HalGpioFmuxEnable(spiCtl[index].cfg.ssn_pin,Bit_DISABLE);
        HalGpioSet(spiCtl[index].cfg.ssn_pin, Bit_DISABLE);
        HalGpioPinInit(spiCtl[index].cfg.ssn_pin, GPIO_OUTPUT);
    }

    if(spiCtl[index].cfg.int_mode == false)
    {
        ret = HalSpiXmitPolling(SPIx, tx_buf, rx_buf, len);
        if(spiCtl[index].cfg.force_cs == true)
        {
            HalGpioFmuxEnable(spiCtl[index].cfg.ssn_pin,Bit_ENABLE);
        }
        if(ret)
        {
            return ERR_TIMEOUT;
        }
    }
    else
    {
        HalSpiIntDisable(index);

        if(SPIx->SR & TX_FIFO_NOT_FULL)
        {
            uint8_t dummy[8] = {0};

            hal_pwrmgr_lock((per_module_t)(MOD_SPI0 + index));
            
            spiCtl[index].txBufCtl.bufOffset = (len >= 8)?8:len;

//            Ssix->RXFTLR = _tx_len - 1;
            HalSpiWriteFifo(SPIx, spiCtl[index].txBufCtl.bufOffset, (tx_buf!=NULL)?tx_buf:dummy);
        }

        spiCtl[index].busy = true;
        HalSpiIntEnable(index, 0x11);
    }

    return ERR_NONE;
}

ErrCode_t HalSpiSlaveTxPrepare(AP_SSI_TypeDef* SPIx, uint8_t* tx_buf, uint16_t len)
{
    SPI_INDEX_e index = SPI0;
    
    if(SPIx != AP_SPI0 && SPIx != AP_SPI1)
    {
        return ERR_NOT_SUPPORTED;
    }
    if(tx_buf == NULL || len ==0)
	{
		return ERR_INVALID_DATA;
	}
    if(SPIx == AP_SPI1)
    {
        index = SPI1;
    }
    
    spiCtl[index].txBufCtl.buf = tx_buf;
    spiCtl[index].txBufCtl.bufSize = len;
    spiCtl[index].txBufCtl.bufOffset = 0;
    spiCtl[index].rxBufCtl.buf = NULL;
    spiCtl[index].rxBufCtl.bufOffset = 0;
	if(SPIx->SR & 0x10)
    {
		SPIx->IMR |= BIT(0);
		return ERR_NONE;
	}
	if(len > 8 - SPIx->TXFLR)
    {
		len = 8 - SPIx->TXFLR;
	}
	for(uint8_t i=0; i<len; i++)
    {
		SPIx->DataReg = tx_buf[i];
	}
	spiCtl[index].txBufCtl.bufOffset = len;
    SPIx->IMR |= BIT(0);
    
    spiCtl[index].busy = true;
    
	return ERR_NONE;
}

ErrCode_t HalSpiSetIntMode(SPI_INDEX_e index, bool en)
{
	if(index > SPI1)
	{
		return ERR_DATA_SIZE;
	}
    spiCtl[index].cfg.int_mode = en;

    if(en)
    {
        HalSpiIntEnable(index, 0x10);
    }
    else
    {
        HalSpiIntDisable(index);
    }

    return ERR_NONE;
}

ErrCode_t HalSpiSetForceCs(SPI_INDEX_e index, bool en)
{
	if(index > SPI1)
    {
        return ERR_NOT_SUPPORTED;
    }
    spiCtl[index].cfg.force_cs = en;
    return ERR_NONE;
}

bool HalSpiGetTransmitState(SPI_INDEX_e index)
{
	AP_SSI_TypeDef* SPIx = NULL;
    
    SPIx = (index == SPI0) ? AP_SPI0 : AP_SPI1;
    return (SPIx->SR&SPI_BUSY)||spiCtl[index].busy;
}

ErrCode_t HalSpiMasterConfig(AP_SSI_TypeDef* SPIx, spi_Cfg_t *cfg)
{
    uint16_t baud_temp;
    SPI_INDEX_e index = SPI0;
    int pclk = clk_get_pclk();
	if(SPIx != AP_SPI0 && SPIx != AP_SPI1)
    {
        return ERR_NOT_SUPPORTED;
    }
	if(cfg->is_slave)
	{
	 return   ERR_IO_CONFILCT;
	}
	if(cfg->sclk_pin >=GPIO_NUM || cfg->sclk_pin == cfg->ssn_pin ||  cfg->sclk_pin == cfg->MOSI ||  cfg->sclk_pin == cfg->MISO)
	{
		return ERR_IO_CONFILCT;
	}
	if(cfg->ssn_pin>=GPIO_NUM  ||  cfg->ssn_pin == cfg->MOSI ||  cfg->ssn_pin == cfg->MISO)
	{
		return ERR_IO_CONFILCT;
	}
	if(cfg->MOSI>=GPIO_NUM  ||  cfg->MOSI == cfg->MISO)
	{
		return ERR_IO_CONFILCT;
	}
//	if(cfg->MISO>=GPIO_NUM)
//	{
//		return ERR_IO_CONFILCT;
//	}
	if(cfg->spi_tmod>SPI_RXD)
	{
		return ERR_NOT_SUPPORTED;
	}
	if(cfg->spi_scmod>SPI_MODE3)
	{
		return ERR_NOT_SUPPORTED;
	}
	if(cfg->spi_dfsmod < SPI_MINBYTE || cfg->spi_dfsmod > SPI_MAXBYTE)
	{
		return ERR_NOT_SUPPORTED;
	}  
    if(SPIx == AP_SPI1)
    {
        index = SPI1;
    }

    osal_memcpy(&spiCtl[index].cfg, cfg, sizeof(spi_Cfg_t));
    
    spiCtl[index].busy = false;
    spiCtl[index].enable = true;
    spiCtl[index].cfg.is_slave = false;
    
    hal_clk_gate_enable((per_module_t)(MOD_SPI0+index));
    HalSpiPinInit(index, cfg->sclk_pin, cfg->ssn_pin, cfg->MOSI, cfg->MISO);
    
    SPIx->SSIEN = 0;  //DISABLE_SPI;
    SPI_MASTER_SELECT(index);
    SPIx->CR0= ((SPIx->CR0) & 0xfffffc30)|((unsigned int)(spiCtl[index].cfg.spi_dfsmod))|(cfg->spi_scmod<<6)|(cfg->spi_tmod<<8);
    baud_temp = (pclk + (cfg->baudrate>>1)) / cfg->baudrate;

    if(baud_temp<2)
    {
        baud_temp = 2;
    }
    else if(baud_temp>65534)
    {
        baud_temp =65534;
    }

    SPIx->BAUDR= baud_temp;   // set clock(round)
    SPIx->TXFTLR=4;    // set fifo threshold to triggle interrupt
    SPIx->RXFTLR=0;
    SPIx->IMR = 0x00;
    SPIx->SER=1;      //enable slave device
    SPIx->SSIEN = 1;  //ENABLE_SPI;
    
    if(cfg->int_mode)
        HalSpiIntEnable(index, 0x10);
    else
        HalSpiIntDisable(index);
    
    return ERR_NONE;
}

ErrCode_t HalSpiSlaveConfig(AP_SSI_TypeDef* SPIx, spi_Cfg_t *cfg)
{
    SPI_INDEX_e index = SPI0;
	if(SPIx != AP_SPI0 && SPIx != AP_SPI1)
    {
        return ERR_NOT_SUPPORTED;
    }
	if(!cfg->is_slave)
	{
	 return   ERR_IO_CONFILCT;
	}

    if(cfg->sclk_pin >=GPIO_NUM || cfg->sclk_pin == cfg->ssn_pin ||  cfg->sclk_pin == cfg->MOSI ||  cfg->sclk_pin == cfg->MISO)
	{
		return ERR_IO_CONFILCT;
	}
	if(cfg->ssn_pin>=GPIO_NUM  ||  cfg->ssn_pin == cfg->MOSI ||  cfg->ssn_pin == cfg->MISO)
	{
		return ERR_IO_CONFILCT;
	}
	if(cfg->MOSI>=GPIO_NUM  ||  cfg->MOSI == cfg->MISO)
	{
		return ERR_IO_CONFILCT;
	}
	if(cfg->MISO>=GPIO_NUM)
	{
		return ERR_IO_CONFILCT;
	}
	if(cfg->spi_tmod>SPI_RXD)
	{
		return ERR_NOT_SUPPORTED;
	}
	if(cfg->spi_scmod>SPI_MODE3)
	{
		return ERR_NOT_SUPPORTED;
	}
	if(cfg->spi_dfsmod < SPI_MINBYTE || cfg->spi_dfsmod > SPI_MAXBYTE)
	{
		return ERR_NOT_SUPPORTED;
	}
    if(SPIx == AP_SPI1)
    {
        index = SPI1;
    }

    osal_memcpy(&spiCtl[index].cfg, cfg, sizeof(spi_Cfg_t));
    
    spiCtl[index].busy = false;
    spiCtl[index].enable = true;
    spiCtl[index].cfg.is_slave = true;
    
    hal_clk_gate_enable((per_module_t)(MOD_SPI0 + index));
    if(spiCtl[index].cfg.int_mode)
        HalSpiIntEnable(index, 0x11);
    else
        HalSpiIntDisable(index);
    
    HalSpiPinInit(index, spiCtl[index].cfg.sclk_pin, spiCtl[index].cfg.ssn_pin, spiCtl[index].cfg.MISO, spiCtl[index].cfg.MOSI);

	SPIx->SSIEN = 0;	//disable SPI
	SPI_SLAVE_SELECT(index);
	SPIx->CR0 = ((SPIx->CR0 & 0xfffffc30) | ((unsigned int)(spiCtl[index].cfg.spi_dfsmod)) | ((unsigned int)(spiCtl[index].cfg.spi_scmod) << 6) | ((unsigned int)SPI_TRXD << 8)) ;
	SPIx->TXFTLR = 4;
	SPIx->RXFTLR = 0;
    
    SPIx->SSIEN = 1;

    return ERR_NONE;
}

/**************************************************************************************
@fn          HalSpiDeinit

@brief       This function will deinit the spi you select.

input parameters

@param         hal_spi_t* spi_ptr: spi module handle.


output parameters

@param       None.

@return
            SUCCESS
            ERR_INVALID_PARAM
 **************************************************************************************/
ErrCode_t HalSpiDeinit(SPI_INDEX_e index)
{
	if(index >SPI1)
	{
		return ERR_NOT_SUPPORTED;
	}
	HalSpiDisable(index);
	if(index == SPI0)
	{
		hal_pwrmgr_unregister(MOD_SPI0);
	}
	else if(index == SPI1)
	{
		hal_pwrmgr_unregister(MOD_SPI1);
	}
	return ERR_NONE;
}

/**************************************************************************************
@fn          HalSpiInit

@brief       it is used to init spi module.

input parameters
@param       None

output parameters
@param       None.

@return      None.
 **************************************************************************************/
ErrCode_t HalSpiInit(SPI_INDEX_e channel)
{
    ErrCode_t ret = ERR_NONE;

    if(channel == SPI0)
    {
        ret = hal_pwrmgr_register(MOD_SPI0, HalSpi0SleepHandler, HalSpi0WakeupHandler);

        if(ret == ERR_NONE)
            osal_memset(&spiCtl[0], 0, sizeof(SpiCtl_t));

        return ret;
    }
    else if(channel == SPI1)
    {
        ret = hal_pwrmgr_register(MOD_SPI1, HalSpi1SleepHandler, HalSpi1WakeupHandler);

        if(ret == ERR_NONE)
            osal_memset(&spiCtl[1], 0, sizeof(SpiCtl_t));

        return ret;
    }

    return ERR_INVALID_PARAM;
}

#if DMAC_USE
ErrCode_t HalSpiDmaSet(SPI_INDEX_e index, bool ten, bool ren)
{
	if(index >SPI1)
	{
		return ERR_NOT_SUPPORTED;
	}
    spiCtl[index].cfg.dma_rx_enable = ren;
    spiCtl[index].cfg.dma_tx_enable = ten;
    return ERR_NONE;
}
#endif
